package com.azzaou.dao.impl;


import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.azzaou.dao.IDAO;


public abstract class AbstractDAO<E> implements IDAO<E>
{
  /**
   * Logger of the clas
   */
//  protected static final Logger LOGGER = LoggerFactory
//      .getLogger(AbstractDAO.class);

  /**
   * Usine de sessions Hibnernate
   */
  private SessionFactory sessionFactory;

  /**
   * injecteur Spring de sessionFactory
   * 
   * @param asessionFactory
   *          Usine de sessions hibernate
   */
  public void setSessionFactory(SessionFactory asessionFactory)
  {
    this.sessionFactory = asessionFactory;
  }

  /**
   * Retourne la session courante d'hibernate
   * 
   * @return objet session
   */
  @Override
  public Session getCurrentSession()
  {
    return sessionFactory.getCurrentSession();
  }

  /**
   * Return the name of class 
   * 
   * @return the full name of the class per package
   */
  @Override
  public abstract String getPojoClassName();

  /**
   * Method to persist Element
   * 
   * @param transientInstance
   *          : Object to persist
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public void persist(E transientInstance) throws RuntimeException
  {
    getCurrentSession().persist(transientInstance);

  }

  /**
   * Generic method for saveOrUpdate
   * 
   * @param instance
   *          : Object to saveOrUpdate
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public void saveOrUpdate(E instance) throws RuntimeException
  {
    getCurrentSession().saveOrUpdate(instance);
  }

  /**
   * Generic method for Update element
   * 
   * @param instance
   *          : Object to Update
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public void update(E instance) throws RuntimeException
  {
    getCurrentSession().update(instance);
  }

  /**
   * Generic method for merge element
   * 
   * @param instance
   *          : Object to merge
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public void merge(E instance) throws RuntimeException
  {
    getCurrentSession().merge(instance);
  }

  /**
   * Generic method for delete element
   * 
   * @param persistentInstance
   *          : Object to delete
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public void delete(E persistentInstance) throws RuntimeException
  {
    getCurrentSession().delete(persistentInstance);
  }

  /**
   * method to Execute execute hql query
   * 
   * @param hqlQuery
   *          : query hql to execute
   * @param map
   *          : Parameters
   * @return List<E>: list of Object result
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public List<E> executerRequeteHql(String hqlQuery, HashMap map)
      throws RuntimeException
  {
    return executerRequeteHql(hqlQuery, map, null);
  }

  /**
   * method to Execute execute hql query
   * 
   * @param hqlQuery
   *          : query hql to execute
   * @param map
   *          : Parameters
   * @param maxResult
   *          : specifier the number of result to retrieve
   * @return List<E>: list of Object result
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public List<E> executerRequeteHql(String hqlQuery, HashMap map, Long maxResult)
      throws RuntimeException
  {
    List results = null;
    if (hqlQuery != null && !"".equals(hqlQuery))
    {
      Query query = getCurrentSession().createQuery(hqlQuery);
      if (maxResult != null)
      {
        query.setMaxResults(maxResult.intValue());
      }
      if (map != null && !map.isEmpty())
      {
        Iterator it = map.keySet().iterator();
        while (it.hasNext())
        {
          String param = (String)it.next();
          List valueList = (List)map.get(param);
          if (valueList != null && valueList.size() > 0)
          {
            if (valueList.size() == 1)
            {
              query.setParameter(param, valueList.get(0));
            }
            else
            {
              query.setParameterList(param, valueList);
            }
          }
        }
      }
      results = query.list();
    }
    return results;
  }

  /**
   * method to Execute update query
   * 
   * @param queryUpdate
   *          : query
   * @param map
   *          : Parameters
   * @return int: -1
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public int executerRequeteUpdate(String queryUpdate, HashMap map)
      throws RuntimeException
  {

    int queryUpdateReturn;
    if (!StringUtils.isBlank(queryUpdate))
    {
      Query query = getCurrentSession().createQuery(queryUpdate);

      if (map != null && !map.isEmpty())
      {
        Iterator it = map.keySet().iterator();
        while (it.hasNext())
        {
          String param = (String)it.next();
          List valueList = (List)map.get(param);
          if (valueList != null && valueList.size() > 0)
          {
            if (valueList.size() == 1)
            {
              query.setParameter(param, valueList.get(0));
            }
            else
            {
              query.setParameterList(param, valueList);
            }
          }
        }
      }
      queryUpdateReturn = query.executeUpdate();
    }
    else
    {
      queryUpdateReturn = -1;
    }
    return queryUpdateReturn;
  }

  /**
   * generic method to Execute search by id query
   * 
   * @param id
   *          : id to search
   * @return E: Type of class
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public E findById(Long id) throws RuntimeException
  {
    E instance;
    if (id == null)
    {
      instance = null;
    }
    else
    {
      instance = (E)getCurrentSession().get(getPojoClassName(), id);
    }
    return instance;
  }

  /**
   * method getAllInstances * @return List<E>: list of class
   * 
   * @throws RuntimeException
   *           : Exception
   */
  @Override
  public List<E> getAllInstances() throws RuntimeException
  {
    List<E> results = getCurrentSession().createCriteria(getPojoClassName())
        .list();
    return results;
  }

}